//Copyright (c) 2012, peter.ducai@gmail.com
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following 
//conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
//in the documentation and/or other materials provided with the distribution.
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
//OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
//OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
//OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
//OF SUCH DAMAGE.
package com.daemonna.fluentlee_core.server;

import com.daemonna.fluentlee_core.job.schedule;
import com.daemonna.fluentlee_core.managers.execution_manager;
import com.daemonna.fluentlee_core.managers.report_manager;
import com.daemonna.fluentlee_core.managers.schedule_cleaner;
import com.daemonna.fluentlee_core.pools.data_pool;
import com.daemonna.fluentlee_core.pools.schedule_pool;
import com.daemonna.fluentlee_core.pools.server_settings_pool;
import com.daemonna.fluentlee_core.readers.schedule_reader;
import com.daemonna.fluentlee_core.utils.file_util;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.xml.sax.SAXException;

/*
 * @author peter 'daemonna' ducai @author peter.ducai@gmail.com @author
 * http://code.google.com/p/fluentlee/
 */

/*
 * job server is master server which listens for incoming job packages (many
 * schedule files)
 */
public class job_server {

    private file_util fut = new file_util();

    public job_server() throws IOException, SQLException, Exception {

        //check for aviable schedules, load pool
        check_local_schedules();

        //check if we run local or server version
        check_allowance();
    }

    /*
     * if any .schedule files found, add them to schedule_pool + discard
     * '.schedule' from name
     */
    private void check_local_schedules() {

        File folder = new File("schedules");
        File[] listOfFiles = folder.listFiles();

        for (int i = 0; i < listOfFiles.length; i++) {

            if (listOfFiles[i].isFile()) {
                String files = listOfFiles[i].getName();
                if (files.endsWith(".schedule") || files.endsWith(".SCHEDULE")) {
                    files.toLowerCase();
                    schedule_pool.getInstance().scheds[i] = new schedule();
                    schedule_pool.getInstance().scheds[i].id = i;
                    
                    String ff=files.substring(0,files.length()-9);
                    schedule_pool.getInstance().scheds[i].name = ff;
                }
            }
        }
    }

    private void check_client_schedules() {

        File folder = new File("schedules/client");
        File[] listOfFiles = folder.listFiles();

        for (int i = 0; i < listOfFiles.length; i++) {

            if (listOfFiles[i].isFile()) {
                String files = listOfFiles[i].getName();
                if (files.endsWith(".schedule") || files.endsWith(".SCHEDULE")) {
                    //add all schedules to schedule_pool
//                    schedule_pool.getInstance().scheds[i] = new schedule();
//                    schedule_pool.getInstance().scheds[i].id = i;
//                    schedule_pool.getInstance().scheds[i].name = files;
                }
            }
        }
    }

    /*
     * check if we are running local or server/remote version
     */
    private void check_allowance() throws IOException, SQLException, Exception {


        if (!server_settings_pool.getInstance().allow_remote_jobs) {

            System.out.println("===========================================================================================");
            System.out.println("JOB SERVER: running LOCAL instance. change security.xml if want to allow remote connections");
            System.out.println("===========================================================================================");

            run_local();

        } else {
            System.out.println("===========================================================================================");
            System.out.println("JOB SERVER: running SERVER instance. change security.xml if dont want allow any connections");
            System.out.println("===========================================================================================");

            run_schedule_eater();

        }

    }

    private void run_local() throws SQLException, Exception {

        for (int z = 0; z < schedule_pool.getInstance().scheds.length; z++) {

            if (schedule_pool.getInstance().scheds[z] != null) {
                try {
                    
                    //read schedule file and prepare all data (insert them into pool)
                    schedule_reader schedr = new schedule_reader();
                    schedr.read_schedule(schedule_pool.getInstance().scheds[z].name, z);

                    //if dry-run is true, dont execute jobs!!!
                    if (!data_pool.getInstance().dry_run) {
                        
                        //execute ready jobs from schedule_pool
                        execution_manager execman = new execution_manager();
                        execman.execute_schedule(z);
                        
                        report_manager reporter = new report_manager();
                        
                    } else {
                        System.out.println("DRY RUN ===========================================>");
                    }

                } catch (ParserConfigurationException ex) {
                    Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SAXException ex) {
                    Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
                } catch (XPathExpressionException ex) {
                    Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InterruptedException ex) {
                    Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
                }

                System.out.println("FINISHed with schedule~~~~~~~~~~~~");
            }
        }
        
        //TODO uncomment cleaner for prod build
//        schedule_cleaner cleaner = new schedule_cleaner();
//        cleaner.clean_jobs();
//        cleaner.clean_schedule_files();
          
    }

    //TODO schedule eater
    private void run_schedule_eater() {
        FileInputStream fin = null;
        try {
            //run file-server which will accept remotely sent schedule files

            SSLContext context;
            KeyManagerFactory kmf;
            KeyStore ks;
            char[] storepass = "newpass".toCharArray();
            char[] keypass = "wshr.ut".toCharArray();
            String storename = "newstore";

            context = SSLContext.getInstance("TLS");
            kmf = KeyManagerFactory.getInstance("SunX509");
            fin = new FileInputStream(storename);
            ks = KeyStore.getInstance("JKS");

            ks.load(fin, storepass);
            fin.close();
            kmf.init(ks, keypass);

            context.init(kmf.getKeyManagers(), null, null);

            SSLServerSocketFactory ssf = context.getServerSocketFactory();

            //start SSL socket
            ServerSocket ss = ssf.createServerSocket(5432);
            while (true) {
                Socket s = ss.accept();
                PrintStream out = new PrintStream(s.getOutputStream());
                out.println("Hi");
                out.close();
                s.close();
            }

        } catch (FileNotFoundException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyManagementException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(job_server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /*
     * list all .schedule files in 'schedules' dir and load them to
     * schedule_pool
     */
}
